﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using Redbrick.Silverlight.Serialization;

namespace DeenGames.Utils
{
    ///<summary>
     /// Helper class for cross-provider functions, like hashing/encryption.
     ///</summary>
    static class PersistentStorageHelper
    {
        // Used primarily with cookies, to prevent conflicts from multiple apps
        internal static string appIdentifier;
        private static SHA256Managed hashProvider = new SHA256Managed();
        private static AesManaged encryptionProvider = new AesManaged();

        // Used for encyrption; our secret key. Guaranteed to be pretty strong. (32 bytes)
        // It's possible to reverse-engineer, but you can only screw up your own data.
        private static string SECRET_KEY = "dRugAc9pRepHur7qAd+-breb3tucraba";

		/// <summary>
		/// Used to hash variable names when we store variables. Two variables
		/// hashing to the same value means we accidentally deleted one with
		/// the new variable. Big "uh-oh."
		/// </summary>
		/// <param name="key"></param>
		/// <returns></returns>
        internal static string Hash(string key)
        {
            byte[] raw = Encoding.UTF8.GetBytes(key);
            byte[] hash = hashProvider.ComputeHash(raw, 0, raw.Length);
            string base64 = Convert.ToBase64String(hash);
            base64 = base64.Substring(0, base64.Length - 2); // trim "=" from end
            // convert / and +, which might not be legit characters
            base64 = base64.Replace('+', '_');
            base64 = base64.Replace('/', '-');
            return base64;
        }

		/// <summary>
		/// Occasionally convenient for some of our storage providers.
		/// </summary>
		/// <param name="dataToEncrypt"></param>
		/// <returns></returns>
        //internal static string Encrypt(string dataToEncrypt)
        //{
        //    // Initialise
        //    AesManaged encryptor = new AesManaged();

        //    // Set the key
        //    // Must be 256 bits (32 bytes)
        //    encryptor.Key = Encoding.UTF8.GetBytes(SECRET_KEY);

        //    // Must be 16 bytes; so use half the key
        //    encryptor.IV = Encoding.UTF8.GetBytes(SECRET_KEY.Substring(0, 16));

        //    // create a memory stream
        //    using (MemoryStream encryptionStream = new MemoryStream())
        //    {
        //        // Create the crypto stream
        //        using (CryptoStream encrypt = new CryptoStream(encryptionStream, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
        //        {
        //            // Encrypt
        //            byte[] utfD1 = UTF8Encoding.UTF8.GetBytes(dataToEncrypt);
        //            encrypt.Write(utfD1, 0, utfD1.Length);
        //            encrypt.FlushFinalBlock();
        //            encrypt.Close();

        //            // Return the encrypted data
        //            return Convert.ToBase64String(encryptionStream.ToArray());
        //        }
        //    }
        //}

        //internal static string Decrypt(string encryptedString)
        //{
        //    // Initialise
        //    AesManaged decryptor = new AesManaged();
        //    byte[] encryptedData = Convert.FromBase64String(encryptedString);

        //    // Set the key
        //    // Must be 256 bits (32 bytes)
        //    decryptor.Key = Encoding.UTF8.GetBytes(SECRET_KEY);

        //    // Must be 16 bytes; so use half the key
        //    decryptor.IV = Encoding.UTF8.GetBytes(SECRET_KEY.Substring(0, 16));

        //    // create a memory stream
        //    using (MemoryStream decryptionStream = new MemoryStream())
        //    {
        //        // Create the crypto stream
        //        using (CryptoStream decrypt = new CryptoStream(decryptionStream, decryptor.CreateDecryptor(), CryptoStreamMode.Write))
        //        {
        //            // Encrypt
        //            decrypt.Write(encryptedData, 0, encryptedData.Length);
        //            decrypt.Flush();
        //            decrypt.Close();

        //            // Return the unencrypted data
        //            byte[] decryptedData = decryptionStream.ToArray();
        //            return UTF8Encoding.UTF8.GetString(decryptedData, 0, decryptedData.Length);
        //        }
        //    }
        //}

		/// <summary>
		/// Serialize any object into a base64 string. Relies on a third-party serializer.
		/// </summary>
		/// <param name="o"></param>
		/// <returns></returns>
        internal static string Serialize<_type>(_type o)
        {
            return System.Convert.ToBase64String(SilverlightSerializer.Serialize(o) );
        }

		/// <summary>
		/// Deserialize any object's base64 string. Relies on a third-party serializer.
		/// </summary>
		/// <param name="s"></param>
		/// <returns></returns>
        internal static _type Deserialize<_type>(string s)
        {
            return SilverlightSerializer.Deserialize<_type>(Convert.FromBase64String(s));
        }
    }
}
